package com.asimplefox.service.stand;

import com.asimplefox.configs.GoogleEmailConfig;
import com.asimplefox.entity.Invite;
import com.asimplefox.entity.Role;
import com.asimplefox.entity.User;
import com.asimplefox.entity.vo.RegisterVo;
import com.asimplefox.entity.vo.UserVo;
import com.asimplefox.service.IInviteService;
import com.asimplefox.service.IRoleService;
import com.asimplefox.service.IUserService;
import com.asimplefox.service.abst.ResultU;
import io.github.kloping.date.FrameUtils;
import io.github.kloping.judge.Judge;
import io.github.kloping.rand.RandomUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author github.kloping
 */
@Service
public class AuthService implements ResultU {
    private static final String EMAIL_REGEX = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";

    public static boolean isValidEmail(String email) {
        return email != null && email.matches(EMAIL_REGEX);
    }

    private Map<String, String> email2code = new ConcurrentHashMap<>();

    public static final char[] ALL = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};

    public String getRandCode() {
        return getRandCode(6);
    }

    public String getRandCode(int w) {
        char[] chars = new char[w];
        for (int i = 0; i < w; i++) {
            chars[i] = ALL[RandomUtils.RANDOM.nextInt(ALL.length)];
        }
        return new String(chars);
    }

    @Autowired
    GoogleEmailConfig googleEmailConfig;

    public boolean requestCode(String email) {
        if (email2code.containsKey(email)) return false;
        String code = getRandCode();
        googleEmailConfig.sendMailSimple(email, "Check your verification code", "Valid for 5 minutes\n"
                + "If you haven't done it, please ignore it\n"
                + "Your verification code is <h1>" + code + "</h1>");
        email2code.put(email, code);
        FrameUtils.SERVICE.schedule(() -> {
            email2code.remove(email);
        }, 5, TimeUnit.MINUTES);
        return true;
    }

    public boolean checkCode(String email, String code) {
        return email2code.getOrDefault(email, "").equals(code);
    }

    @Autowired
    IUserService userService;

    @Autowired
    IRoleService roleService;

    @Autowired
    IInviteService iInviteService;

    @Autowired
    LoginDetailService loginDetailService;

    public Object register(RegisterVo vo, HttpServletRequest request, HttpServletResponse response) {
        if (vo.getUsername().length() < 5) {
            return fail("用户名长度不能小于5");
        }
        if (vo.getPassword().length() < 6) {
            return fail("密码长度不能小于6");
        }
        if (Judge.isNotEmpty(vo.getIcode())) {
            Invite inviteer = iInviteService.lambdaQuery().eq(Invite::getPcode, vo.getIcode()).one();
            if (inviteer == null) {
                return fail("邀请码无效");
            }
        }
        User ou = userService.lambdaQuery().eq(User::getEmail, vo.getEmail()).one();
        if (ou != null) return fail("邮箱已被注册");

        User user = new User();
        user.setNickname(vo.getUsername());
        user.setUsername(vo.getUsername());
        user.setPwd(vo.getPassword());
        user.setEmail(vo.getEmail());
        user.setTelephone("");
        user.setReg("email");
        userService.save(user);
        roleService.save(new Role().setUserId(user.getId()).setUserRole("user"));

        email2code.remove(vo.getEmail());

        Invite invite = new Invite();
        invite.setUserId(user.getId());
        invite.setPcode(iInviteService.getAnyCodee());
        if (Judge.isNotEmpty(vo.getIcode())) {
            invite.setBcode(vo.getIcode());
        }
        iInviteService.save(invite);
        return loginDetailService.loginNow(new UserVo(vo.getUsername(), vo.getPassword()), request, response);
    }

    /**
     * 检测指定username 是否存在
     *
     * @param id
     * @return true: 不存在
     */
    public Object check(String id) {
        return userService.lambdaQuery().eq(User::getUsername, id).one() == null;
    }
}
